package com.cqfae.deploycentral.app.services.impl;

import com.cqfae.deploycentral.api.utils.IdGenerator;
import com.cqfae.deploycentral.app.base.BaseConstants;
import com.cqfae.deploycentral.app.dao.entity.AppInfo;
import com.cqfae.deploycentral.app.dao.entity.ReportInfoTag;
import com.cqfae.deploycentral.app.dao.mapper.AppInfoMapper;
import com.cqfae.deploycentral.app.dao.mapper.ReportInfoTagMapper;
import com.cqfae.deploycentral.app.services.AppInfoService;
import com.cqfae.deploycentral.app.utils.ConvertUtil;
import com.cqfae.deploycentral.app.utils.GsonUtils;
import com.cqfae.deploycentral.app.utils.NullUtil;
import com.cqfae.deploycentral.app.web.request.AppInfoRequest;
import com.cqfae.deploycentral.app.web.response.IPage;
import com.cqfae.deploycentral.app.web.vo.AppInfoVo;
import com.cqfae.deploycentral.app.web.vo.SelectedVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by JIANGLU009 on 2017/8/2.
 */
@Service
@Transactional
public class AppInfoServiceImpl implements AppInfoService {

    private static Logger logger = LoggerFactory.getLogger(AppInfoServiceImpl.class);

    public static final String PROJECT_NAME_REPEAT = "项目名称重复";

    public static final String PROJECT_ID_NULL = "项目ID为空";

    public static final String UPDATE_ID_NULL = "更新ID为空";

    public static final String BUILD_CODE_NULL = "未发现该构建类型业务编号";

    public static final String PACKAGE_CODE_NULL = "未发现该构建类型业务编号";

    public static final String CLASS_STRING = "class java.lang.String";

    public static final Integer NOTHING_TO_DO = 0;

    public static final String TRIM_ERROR = "字符串去空格错误";

    public static final String APP_USED = "不能删除测试报告已使用的项目";

    private static final String APP_NAME = "appName";
    //排序条件
    private static final String SQL_ORDER = "CREATE_TIME";

    // 获取ID
    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private AppInfoMapper appInfoMapper;

    @Autowired
    private ReportInfoTagMapper reportInfoTagMapper;


    @Override
    public Integer add(AppInfoVo appInfoVo) {
        AppInfo appInfo = new AppInfo();
        BeanUtils.copyProperties(appInfoVo, appInfo);
        if (NullUtil.isNotEmpty(appInfo)) {
            // 对string类型的属性做trim
            trimStr(appInfo);
            // 验证编码
            codeCheck(appInfo);
            // 项目名称重复验证
            Assert.isTrue(!isAppNameExist(appInfo, false), PROJECT_NAME_REPEAT);
            // 设置新增ID
            appInfo.setId(idGenerator.nextId());
            // 设置新增操作者和时间
            appInfo.setCreateBy("123");
            appInfo.setCreateTime(new Date());
            // 设置更新操作者和时间
            appInfo.setUpdateBy("123");
            appInfo.setUpdateTime(new Date());
            // 设置项目组信息
            appInfo.setProjectKey(appInfoVo.getProjectCode());
            return appInfoMapper.insert(appInfo);
        } else {
            return NOTHING_TO_DO;
        }

    }

    /**
     * 更新
     *
     * @param appInfoVo
     * @return
     */
    @Override
    public Integer edit(AppInfoVo appInfoVo) {
        AppInfo appInfo = new AppInfo();
        BeanUtils.copyProperties(appInfoVo, appInfo);
        if (NullUtil.isNotEmpty(appInfo)) {
            // 对string类型的属性做trim
            trimStr(appInfo);
            // 验证编码
            codeCheck(appInfo);
            // 项目名称重复验证
            Assert.isTrue(!isAppNameExist(appInfo, true), PROJECT_NAME_REPEAT);
            // 设置更新操作者和时间
            appInfo.setUpdateBy("123");
            appInfo.setUpdateTime(new Date());
            // 设置项目组信息
            appInfo.setProjectKey(appInfoVo.getProjectCode());
            // 组装更新条件
            Example example = new Example(AppInfo.class);
            example.createCriteria().andEqualTo("id", appInfoVo.getId());
            return appInfoMapper.updateByExampleSelective(appInfo, example);
        } else {
            return NOTHING_TO_DO;
        }
    }

    /**
     * 删除
     *
     * @param appInfoVo
     * @return
     */
    @Override
    public Integer delete(AppInfoVo appInfoVo) {
        AppInfo appInfo = new AppInfo();
        BeanUtils.copyProperties(appInfoVo, appInfo);
        if (NullUtil.isNotEmpty(appInfo) && appInfo.getId() != null) {
            // 查询项目
            AppInfo appInfo1 = appInfoMapper.selectOne(appInfo);
            if (appInfo1 != null) {
                // 组装条件
                Example example = new Example(ReportInfoTag.class);
                example.createCriteria().andEqualTo(APP_NAME, appInfo1.getAppName());
                int count = reportInfoTagMapper.selectCountByExample(example);
                // 在测试报告正在使用app时不能删除
                if (count > 0) {
                    Assert.isTrue(false, APP_USED);
                }
                return appInfoMapper.delete(appInfo1);
            }
        }
        return NOTHING_TO_DO;


    }

    /**
     * 链表查询
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public List<AppInfoVo> list(AppInfoRequest request) {
        // 组装条件
        Example example = new Example(AppInfo.class);
        createCriteria(example);
        example.setOrderByClause(SQL_ORDER);
        // 根据条件查询
        List<AppInfo> list = appInfoMapper.selectByExample(example);
        List<AppInfoVo> appInfoVoList = new ArrayList<>();
        // 将实体转换成VO
        for (AppInfo appInfo : list) {
            AppInfoVo vo = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(appInfo), AppInfoVo.class);
            // 验证编码
            codeCheck(vo);
            vo = setCodeName(vo);
            appInfoVoList.add(vo);
        }
        return appInfoVoList;
    }

    /**
     * 翻页查询
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public IPage<AppInfoVo> listByPage(AppInfoRequest request) {
        // 创建翻页对象
        Page<AppInfo> page = PageHelper.startPage(request.getPageNum(), request.getPageSize());
        // 组装查询条件
        Example example = new Example(AppInfo.class);
        createCriteria(example);
        example.orderBy(SQL_ORDER).desc();
        if (StringUtils.isNotBlank(request.getAppName())) {
            example.createCriteria().andLike(APP_NAME, "%" + request.getAppName() + "%");
        }
        if (StringUtils.isNotBlank(request.getProjectCode())) {
            example.createCriteria().andEqualTo("projectKey", request.getProjectCode());
        }
        // 查询并设置数据
        appInfoMapper.selectByExample(example);
        IPage<AppInfoVo> ipage = ConvertUtil.pageToIpage(page, new IPage<AppInfoVo>());
        // 转换VO
        List<AppInfoVo> result = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<AppInfoVo>>() {
        }.getType());
        for (AppInfoVo vo : result) {
            // 验证编码
            codeCheck(vo);
            setCodeName(vo);
        }
        // 设置返回数据
        ipage.setResult(result);
        return ipage;
    }

    /**
     * 根据ID查询一个实体
     *
     * @param request
     * @return
     */
    @Override
    public AppInfoVo getOne(AppInfoRequest request) {
        // 项目ID不能为空
        Assert.isTrue(request.getId() != null, "PROJECT_ID_NULL");
        AppInfo appInfo = new AppInfo();
        // ID和appName都是表唯一的
        appInfo.setId(request.getId());
        appInfo = appInfoMapper.selectOne(appInfo);
        if (appInfo != null) {
            AppInfoVo vo = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(appInfo), AppInfoVo.class);
            vo.setProjectCode(appInfo.getProjectKey());
            // 验证编码
            codeCheck(vo);
            vo = setCodeName(vo);
            return vo;
        } else {
            return null;
        }

    }

    /**
     * 获得所有有效的appName
     *
     * @return
     */
    @Override
    public List<SelectedVo> getAppNameList(AppInfoRequest request) {
        // 组装查询条件
        Example example = new Example(AppInfo.class);
        createCriteria(example);
        if (StringUtils.isNotBlank(request.getQuery())) {
            example.createCriteria().andLike(APP_NAME, "%" + request.getQuery() + "%");
        }
        // 查询并设置数据
        List<AppInfo> appInfoList = appInfoMapper.selectByExample(example);
        List<SelectedVo> selectedVoList = new ArrayList<>();

        for (AppInfo appInfo : appInfoList) {
            String appName = appInfo.getAppName();
            SelectedVo selectedVo = new SelectedVo();
            selectedVo.setCode(appName);
            selectedVo.setName(appName);
            selectedVoList.add(selectedVo);
        }
        return selectedVoList;
    }


    /**
     * 查询条件组装
     *
     * @param example
     */
    private void createCriteria(Example example) {
        example.setOrderByClause("CREATE_TIME DESC");
    }

    /**
     * 根据appName判断项目信息是否重复，重复-true,不重复-false
     * 1、新增情况下，exclude=null，只需要判断数据库是否存在
     * 2、更行情况下，exclude={appName}，需要排除以前appName
     *
     * @param appInfo
     * @param exclude true-更新情况，false-新增情况
     * @return
     */
    private boolean isAppNameExist(AppInfo appInfo, boolean exclude) {
        Example example = new Example(AppInfo.class);
        example.createCriteria().andEqualTo(APP_NAME, appInfo.getAppName());
        // 查询数据库是否存在该code的平台数据
        List<AppInfo> appInfoData = appInfoMapper.selectByExample(example);
        // 不存在的情况下直接返回false
        if (appInfoData == null || appInfoData.isEmpty()) {
            return false;
        } else {
            // 更新情况
            if (exclude) {
                Assert.isTrue(appInfo.getId() != null, UPDATE_ID_NULL);
                AppInfo appInfoOld = new AppInfo();
                appInfoOld.setId(appInfo.getId());
                appInfoOld = appInfoMapper.selectOne(appInfoOld);
                for (AppInfo appInfo1 : appInfoData) {
                    if (!appInfo1.getAppName().equals(appInfoOld.getAppName())) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }
    }

    /**
     * 验证编码
     *
     * @param object
     */
    private void codeCheck(Object object) {
        if (object.getClass() == AppInfo.class) {
            AppInfo appInfo = (AppInfo) object;
            Assert.isTrue(NullUtil.isNotEmpty(BaseConstants.getConstantsCodeMap().get(String.valueOf(appInfo.getBuildType()))),
                    BUILD_CODE_NULL + appInfo.getBuildType());
            Assert.isTrue(NullUtil.isNotEmpty(BaseConstants.getConstantsCodeMap().get(String.valueOf(appInfo.getPackageType()))),
                    PACKAGE_CODE_NULL + appInfo.getPackageType());
        }
        if (object.getClass() == AppInfoVo.class) {
            AppInfoVo vo = (AppInfoVo) object;
            Assert.isTrue(NullUtil.isNotEmpty(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getBuildType()))),
                    BUILD_CODE_NULL + vo.getBuildType());
            Assert.isTrue(NullUtil.isNotEmpty(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getPackageType()))),
                    PACKAGE_CODE_NULL + vo.getPackageType());
        }

    }

    /**
     * 设置code对应的name
     *
     * @param vo
     * @return
     */
    private AppInfoVo setCodeName(AppInfoVo vo) {
        vo.setBuildTypeName(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getBuildType())));
        vo.setPackageTypeName(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getPackageType())));
        return vo;
    }

    /**
     * 对string类型的属性做trim
     *
     * @param object
     * @return
     */
    private Object trimStr(Object object) {
        if (object != null) {
            Class<?> clz = object.getClass();
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                if (field.getGenericType().toString().equals(CLASS_STRING)) {
                    field.setAccessible(true);
                    try {
                        if (null != field.get(object)) {
                            String val = String.valueOf(field.get(object));
                            val = val.trim();
                            field.set(object, val);
                        }
                    } catch (IllegalAccessException e) {
                        logger.error("AppInfoServiceImpl.trimStr IllegalAccessException", e);
                    }
                }
            }
        }
        return object;
    }

}
